package com.distribution.system.service.impl;

import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUnit;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.distribution.common.core.domain.entity.SysUser;
import com.distribution.common.exception.ServiceException;
import com.distribution.common.utils.StringUtils;
import com.distribution.framework.config.ServerConfig;
import com.distribution.system.domain.bo.DefaultProfitConditionBO;
import com.distribution.system.domain.bo.RefreshOrderBO;
import com.distribution.system.domain.converter.CmccDaOrderWebConverter;
import com.distribution.system.domain.converter.UnOrderOperationServiceConverter;
import com.distribution.system.domain.dto.CmccDaOrderListDTO;
import com.distribution.system.domain.dto.OrderStateDTO;
import com.distribution.system.domain.entity.CmccDaAccountDetail;
import com.distribution.system.domain.entity.CmccDaOrder;
import com.distribution.system.domain.entity.CmccDaUpChannelInfo;
import com.distribution.system.domain.req.CmccDaOrderListReq;
import com.distribution.system.domain.vo.LineChartDataVO;
import com.distribution.system.domain.vo.OrderListCountVO;
import com.distribution.system.enums.OrderStatusEnum;
import com.distribution.system.enums.ProfitConditionStatusEnum;
import com.distribution.system.manager.channel.Channel;
import com.distribution.system.manager.channel.ChannelManager;
import com.distribution.system.manager.profitCondition.DefaultProfitConditionEnum;
import com.distribution.system.manager.profitCondition.ProfitCondition;
import com.distribution.system.mapper.CmccDaOrderMapper;
import com.distribution.system.mapper.SysUserMapper;
import com.distribution.system.service.CmccDaAccountDetailService;
import com.distribution.system.service.CmccDaOrderService;
import com.distribution.system.service.CmccDaSubordinateOrderService;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import static com.distribution.common.utils.SecurityUtils.getUserId;

/**
 * 订单服务
 *
 * @author Liping Huo
 * @date 2023/5/22 21:51
 */
@Service("cmccDaOrderService")
@Slf4j
public class CmccDaOrderServiceImpl extends ServiceImpl<CmccDaOrderMapper, CmccDaOrder> implements CmccDaOrderService {
    private static final Logger orderRefreshLog = LoggerFactory.getLogger("orderRefreshLog");
    @Value("${swagger.pathMapping}")
    private String pathMapping;
    @Resource
    ServerConfig serverConfig;
    @Resource
    CmccDaOrderMapper cmccDaOrderMapper;
    @Resource
    CmccDaAccountDetailService cmccDaAccountDetailService;
    @Resource
    SysUserMapper sysUserMapper;
    @Resource
    CmccDaSubordinateOrderService cmccDaSubordinateOrderService;
    @Resource
    CmccDaOrderWebConverter cmccDaOrderWebConverter;
    @Resource
    CmccDaOrderService cmccDaOrderService;
    @Resource
    ChannelManager channelManager;
    @Resource
    UnOrderOperationServiceConverter unOrderOperationServiceConverter;

    @Override
    public List<CmccDaOrder> listCmccDaOrder(CmccDaOrderListDTO cmccDaOrderListDTO) {
        LambdaQueryWrapper<CmccDaOrder> queryWrapper = new LambdaQueryWrapper<>();
        Long userId = !Objects.isNull(cmccDaOrderListDTO.getUserId()) ? cmccDaOrderListDTO.getUserId() : getUserId();
        queryWrapper.eq(CmccDaOrder::getUserId, userId);
        if (!StringUtils.isBlank(cmccDaOrderListDTO.getOpenId())) {
            queryWrapper.eq(CmccDaOrder::getOpenId, cmccDaOrderListDTO.getOpenId());
        }
        if (!Objects.isNull(cmccDaOrderListDTO.getProductTypeId())) {
            queryWrapper.eq(CmccDaOrder::getProductTypeId, cmccDaOrderListDTO.getProductTypeId());
        }
        if (!Objects.isNull(cmccDaOrderListDTO.getOrderStatus())) {
            queryWrapper.eq(CmccDaOrder::getOrderStatus, cmccDaOrderListDTO.getOrderStatus());
        }
        if (!Objects.isNull(cmccDaOrderListDTO.getOrderId())&& !cmccDaOrderListDTO.getOrderId().isEmpty()) {
            queryWrapper.like(CmccDaOrder::getOrderId, cmccDaOrderListDTO.getOrderId());
        }
        if (!Objects.isNull(cmccDaOrderListDTO.getChoosePhone())&& !cmccDaOrderListDTO.getChoosePhone().isEmpty()) {
            queryWrapper.like(CmccDaOrder::getChoosePhone, cmccDaOrderListDTO.getChoosePhone());
        }
        if (!Objects.isNull(cmccDaOrderListDTO.getCustomerName())&& !cmccDaOrderListDTO.getCustomerName().isEmpty()) {
            queryWrapper.like(CmccDaOrder::getCustomerName, cmccDaOrderListDTO.getCustomerName());
        }
        if (!Objects.isNull(cmccDaOrderListDTO.getCustomerPhone())&& !cmccDaOrderListDTO.getCustomerPhone().isEmpty()) {
            queryWrapper.like(CmccDaOrder::getCustomerPhone, cmccDaOrderListDTO.getCustomerPhone());
        }
        if (!Objects.isNull(cmccDaOrderListDTO.getEndTime())) {
            queryWrapper.le(CmccDaOrder::getCreateTime, cmccDaOrderListDTO.getEndTime());
        }
        if (!Objects.isNull(cmccDaOrderListDTO.getBeginTime())) {
            queryWrapper.ge(CmccDaOrder::getCreateTime, cmccDaOrderListDTO.getBeginTime());
        }
        if (!Objects.isNull(cmccDaOrderListDTO.getWriteOffFlag())) {
            queryWrapper.eq(CmccDaOrder::getWriteOffFlag, cmccDaOrderListDTO.getWriteOffFlag());
        }
        queryWrapper.orderByDesc(CmccDaOrder::getCreateTime);
        List<CmccDaOrder> orderList = list(queryWrapper);
        String prefix = serverConfig.getUrl() + pathMapping;
        orderList.forEach(f -> {
            f.setProductImg(prefix + f.getProductImg());
        });
        return orderList;
    }

    @Override
    public List<CmccDaOrder> listCmccDaOrderBySearchValue(CmccDaOrderListDTO cmccDaOrderListDTO) {
        LambdaQueryWrapper<CmccDaOrder> queryWrapper = new LambdaQueryWrapper<>();
        Long userId = !Objects.isNull(cmccDaOrderListDTO.getUserId()) ? cmccDaOrderListDTO.getUserId() : getUserId();
        queryWrapper.eq(CmccDaOrder::getUserId, userId);
        if (!StringUtils.isBlank(cmccDaOrderListDTO.getSearchValue())) {
            queryWrapper.and(wrapper -> wrapper.like(CmccDaOrder::getChoosePhone, cmccDaOrderListDTO.getSearchValue())
                    .or().like(CmccDaOrder::getCustomerName, cmccDaOrderListDTO.getSearchValue())
                    .or().like(CmccDaOrder::getCustomerPhone, cmccDaOrderListDTO.getSearchValue()));
        }
        queryWrapper.orderByDesc(CmccDaOrder::getCreateTime);
        List<CmccDaOrder> orderList = list(queryWrapper);
        String prefix = serverConfig.getUrl() + pathMapping;
        orderList.forEach(f -> {
            f.setProductImg(prefix + f.getProductImg());
        });
        return orderList;
    }

    @Override
    public OrderListCountVO getOrderStatusCount(CmccDaOrderListDTO cmccDaOrderListDTO) {
        return getOrderListCountVO(cmccDaOrderService.listCmccDaOrder(cmccDaOrderListDTO));
    }

    @Override
    public OrderListCountVO getOrderStatusCountBySearchValue(CmccDaOrderListDTO cmccDaOrderListDTO) {
        return getOrderListCountVO(cmccDaOrderService.listCmccDaOrderBySearchValue(cmccDaOrderListDTO));
    }
    private OrderListCountVO getOrderListCountVO(List<CmccDaOrder> cmccDaOrderList){
        int failCount = (int) cmccDaOrderList.stream().filter(f -> "0".equals(f.getOrderStatus())).count();
        int unOrderCount = (int) cmccDaOrderList.stream().filter(f -> "1".equals(f.getOrderStatus())).count();
        int processCount = (int) cmccDaOrderList.stream().filter(f -> "2".equals(f.getOrderStatus())).count();
        int successCount = (int) cmccDaOrderList.stream().filter(f -> "3".equals(f.getOrderStatus())).count();
        return new OrderListCountVO(cmccDaOrderList.size(), failCount, unOrderCount, processCount, successCount);
    }

    //修改订单状态
    @Override
    public void updateOrderByRefreshOrderBO(RefreshOrderBO refreshOrderBo, OrderStatusEnum orderStatusEnum, ProfitConditionStatusEnum profitConditionStatusEnum) {
        log.info("刷新订单对象【{}】状态【{}】描述【{}】", refreshOrderBo, orderStatusEnum.getOrderStatus(), orderStatusEnum.getOrderStatusDesc());
        // 更新
        if (StringUtils.isEmpty(refreshOrderBo.getOrderId()) && StringUtils.isEmpty(refreshOrderBo.getChannelOrderNo())) return;
        cmccDaOrderMapper.updateOrderByRefreshOrderBO(refreshOrderBo, orderStatusEnum.getOrderStatus(), orderStatusEnum.getOrderStatusDesc(), profitConditionStatusEnum.getCode());
        /*CmccDaOrder cmccDaOrder = getOne(new LambdaUpdateWrapper<CmccDaOrder>().eq(CmccDaOrder::getChannelOrderNo, refreshOrderBo.getChannelOrderNo()), false);
        if (cmccDaOrder == null){
            //throw new ServiceException("当前回调订单异常");
            log.error("刷新订单对象时根据渠道方订单号【{}】查询不到订单", refreshOrderBo.getChannelOrderNo());
            return;
        }
        // 向下游代理回调订单状态
        cardDistributionApiService.orderCallback(cmccDaOrder);*/
    }


    @Override
    public void updateOrderState(OrderStateDTO orderStateDTO) {
        SysUser sysUser = sysUserMapper.selectUserById(getUserId());
        if (!sysUser.isOperationSupervisor() && !sysUser.isAdmin()) {
            throw new ServiceException("无权限更改订单状态!");
        }
        CmccDaOrder cmccDaOrderS = cmccDaOrderMapper.selectOne(new LambdaQueryWrapper<CmccDaOrder>().eq(CmccDaOrder::getOrderId, orderStateDTO.getOrderId()));
        if (cmccDaOrderS == null) {
            throw new ServiceException("此订单不存在!");
        }
        if (orderStateDTO.getOrderStatus() == 3) {
            lambdaUpdate()
                    .set(CmccDaOrder::getOrderStatus,3)
                    .set(CmccDaOrder::getOrderStatusDesc, OrderStatusEnum.SUCCESS.getOrderStatusDesc())
                    .set(CmccDaOrder::getProfitConditionStatus,1)
                    .set(CmccDaOrder::getUpdateTime, LocalDateTime.now())
                    .eq(CmccDaOrder::getOrderId,orderStateDTO.getOrderId()).update();
            cmccDaAccountDetailService.updateCmccDaAccountDetail(orderStateDTO.getOrderId(),null);
        } else if (orderStateDTO.getOrderStatus() == 0){
            lambdaUpdate()
                    .set(CmccDaOrder::getOrderStatus,0)
                    .set(CmccDaOrder::getOrderStatusDesc, OrderStatusEnum.FAIL.getOrderStatusDesc())
                    .set(CmccDaOrder::getProfitConditionStatus,0)
                    .set(CmccDaOrder::getUpdateTime, LocalDateTime.now())
                    .eq(CmccDaOrder::getOrderId,orderStateDTO.getOrderId()).update();
        } else if (orderStateDTO.getOrderStatus() == 2){
            lambdaUpdate()
                    .set(CmccDaOrder::getOrderStatus,2)
                    .set(CmccDaOrder::getOrderStatusDesc, OrderStatusEnum.IN_PROGRESS.getOrderStatusDesc())
                    .set(CmccDaOrder::getProfitConditionStatus,0)
                    .set(CmccDaOrder::getUpdateTime, LocalDateTime.now())
                    .eq(CmccDaOrder::getOrderId,orderStateDTO.getOrderId()).update();
        }
        // 更新订单状态
        //cardDistributionApiService.orderCallback(cmccDaOrderS);
    }

    @Override
    public void updateOrderisWriteOff(CmccDaOrder CmccDaOrder) {
        QueryWrapper<CmccDaOrder> cmccDaOrderQueryWrapper = new QueryWrapper<>();
        cmccDaOrderQueryWrapper.eq("order_id",CmccDaOrder.getOrderId());
        CmccDaOrder cmccDaOrderS = cmccDaOrderMapper.selectOne(cmccDaOrderQueryWrapper);
        if (cmccDaOrderS == null) {
            throw new ServiceException("此订单不存在!");
        }else {
            CmccDaOrder.setWriteOffFlag("1");
            cmccDaOrderMapper.updateOrderisWriteOff(CmccDaOrder);
        }
    }

    @Override
    public int getTodayPlaceSuccessOrderCount(Long userId, List<String> productCodeList) {
        LocalDateTime beginTime = DateUtil.beginOfDay(DateUtil.date()).toLocalDateTime();
        LocalDateTime endTime = DateUtil.endOfDay(DateUtil.date()).toLocalDateTime();
        return lambdaQuery().eq(CmccDaOrder::getUserId, userId)
                .in(CmccDaOrder::getProductCode, productCodeList)
                .ne(CmccDaOrder::getOrderStatus, "0")
                .ge(CmccDaOrder::getCreateTime, beginTime)
                .le(CmccDaOrder::getCreateTime, endTime).count();
    }

    /** ============================================================= 订单更新相关 =============================================================== */
    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED, rollbackFor = Exception.class)
    @Override
    public void updateOrderStatusByOrderNo(CmccDaOrder cmccDaOrder) {
        refreshOrder(cmccDaOrder);
    }

    @Override
    public void updateOrderInfoByOrderNo(CmccDaOrder cmccDaOrder) {
        // 订单不为空
        if (cmccDaOrder == null){
            throw new ServiceException("订单不能为空！");
        }
        if (StringUtils.isBlank(cmccDaOrder.getOrderId())){
            throw new ServiceException("订单编号不能为空！");
        }
        Channel defaultChannel = channelManager.getDefaultChannel(cmccDaOrder.getBindChannelInfoId());
        RefreshOrderBO refreshOrderBo = defaultChannel.getRefreshOrderBO(cmccDaOrder);
        if (refreshOrderBo == null) return;
//        log.info("更新信息的订单编号【{}】渠道订单号【{}】", refreshOrderBo.getOrderId(), refreshOrderBo.getChannelOrderNo());
        orderRefreshLog.info("更新信息的订单编号【{}】渠道订单号【{}】", refreshOrderBo.getOrderId(), refreshOrderBo.getChannelOrderNo());
        // 资金明细手机号与订单手机号不一致则更新
        List<CmccDaAccountDetail> list = cmccDaAccountDetailService.lambdaQuery().eq(CmccDaAccountDetail::getOrderId, cmccDaOrder.getOrderId()).list();
        if (!list.isEmpty() && !StringUtils.equals(list.get(0).getChoosePhone(), refreshOrderBo.getPhone())){
            cmccDaAccountDetailService.updateCmccDaAccountDetailPhone(cmccDaOrder.getOrderId(),refreshOrderBo.getPhone());
        }
        refreshOrderInfo(refreshOrderBo, cmccDaOrder);
    }
    // 刷新订单信息
    private void refreshOrderInfo(RefreshOrderBO refreshOrderBo, CmccDaOrder order) {
        // 这里首冲金额单位在各接口中统一为分了，需要转换为元
        try {
            String s = StringUtils.isEmpty(refreshOrderBo.getScMoney()) ? "0" : (new BigDecimal(refreshOrderBo.getScMoney()).divide(new BigDecimal(100), 2, RoundingMode.HALF_UP)).toString();
            refreshOrderBo.setScMoney(s);
        } catch (Exception e) {
            log.error("订单编号为{}的订单刷新状态时首冲金额由分转换为元时出错，原因{}", order.getOrderId(),e.getMessage());
        }
        // 选购号码 激活首冲时间 物流信息 首冲金额不一致则刷新
        lambdaUpdate().eq(CmccDaOrder::getOrderId, order.getOrderId())
                // 卡状态不一致则更新
                .set(!StringUtils.equals(order.getProductStatus(), refreshOrderBo.getProductStatus()), CmccDaOrder::getProductStatus, refreshOrderBo.getProductStatus())
                // 订单选购号码与订单刷新对象选购号码不一致则更新
                .set(!StringUtils.equals(order.getChoosePhone(), refreshOrderBo.getPhone()), CmccDaOrder::getChoosePhone, refreshOrderBo.getPhone())
                // 首冲金额不一致则更新
                .set(!StringUtils.equals(order.getScMoney().toString(), refreshOrderBo.getScMoney()), CmccDaOrder::getScMoney, refreshOrderBo.getScMoney())
                // 激活或首冲时间不一致则更新
                .set(!StringUtils.equals(order.getLimitTime(), refreshOrderBo.getLimitTime()), CmccDaOrder::getLimitTime, refreshOrderBo.getLimitTime())
                // 物流信息不一致则更新
                .set(!StringUtils.equals(order.getLogisticsInfo(), refreshOrderBo.getLogisticsInfo()), CmccDaOrder::getLogisticsInfo, refreshOrderBo.getLogisticsInfo())
                .set(CmccDaOrder::getUpdateTime, DateUtil.date())
                .update();
    }

    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED, rollbackFor = Exception.class)
    @Override
    public void refreshOrder(CmccDaOrder cmccDaOrder) {
        Channel defaultChannel = channelManager.getDefaultChannel(cmccDaOrder.getBindChannelInfoId());
        RefreshOrderBO refreshOrderBO = defaultChannel.getRefreshOrderBO(cmccDaOrder);
        if (refreshOrderBO == null) return;
        refreshOrderStatusByRefreshOrderBO(cmccDaOrder, refreshOrderBO);
    }

    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED, rollbackFor = Exception.class)
    @Override
    public void refreshOrderList(List<CmccDaOrder> orderList, Integer channelId) {
        Channel defaultChannel = channelManager.getDefaultChannel(channelId);
        Map<CmccDaOrder,RefreshOrderBO> refreshOrderBOMap = defaultChannel.getRefreshOrderBOMap(orderList);
        if (refreshOrderBOMap == null || refreshOrderBOMap.isEmpty()) return;
        for (Map.Entry<CmccDaOrder, RefreshOrderBO> entry : refreshOrderBOMap.entrySet()) {
            refreshOrderStatusByRefreshOrderBO(entry.getKey(), entry.getValue());
        }
    }

    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED, rollbackFor = Exception.class)
    @Override
    public void refreshOrderStatusByRefreshOrderBO(CmccDaOrder cmccDaOrder, RefreshOrderBO refreshOrderBo){// 所有渠道查单返回的都是渠道方订单号
//        log.info("更新状态的订单编号【{}】渠道订单号【{}】", refreshOrderBo.getOrderId(), refreshOrderBo.getChannelOrderNo());
        orderRefreshLog.info("更新状态的订单编号【{}】渠道订单号【{}】", refreshOrderBo.getOrderId(), refreshOrderBo.getChannelOrderNo());
        // 订单为空的话则退出
        if (cmccDaOrder == null) {
            return;
        }
        if (StringUtils.isBlank(refreshOrderBo.getChannelOrderNo())){
            refreshOrderBo.setChannelOrderNo(cmccDaOrder.getChannelOrderNo());
        }
        refreshOrderInfo(refreshOrderBo, cmccDaOrder);
        // 或者订单状态为成功 或者订单状态与订单刷新对象的订单状态一致的话则退出
        if ("3".equals(cmccDaOrder.getOrderStatus()) || cmccDaOrder.getOrderStatus().equals(refreshOrderBo.getStatus())) {
            return;
        }
        //refreshOrderBo.setOrderId(cmccDaOrder.getOrderId());
        DefaultProfitConditionBO defaultProfitConditionBO = unOrderOperationServiceConverter.refreshOrderBOToDefaultProfitConditionBO(refreshOrderBo);
        if (isSatisfyProfitCondition(cmccDaOrder, defaultProfitConditionBO)) {
//            log.info("订单编号为【{}】的订单满足激活条件，刷新资金明细", cmccDaOrder.getOrderId());
            orderRefreshLog.info("订单编号为【{}】的订单满足激活条件，刷新资金明细", cmccDaOrder.getOrderId());
            cmccDaAccountDetailService.updateCmccDaAccountDetail(cmccDaOrder.getOrderId(),refreshOrderBo.getPhone());
            // 设置三方信息 订单状态 与 获利条件完成标识
            cmccDaOrderService.updateOrderByRefreshOrderBO(refreshOrderBo, OrderStatusEnum.SUCCESS, ProfitConditionStatusEnum.COMPLETED);
        } else {
            // 设置三方信息 订单状态 与 获利条件完成标识
            cmccDaOrderService.updateOrderByRefreshOrderBO(refreshOrderBo, OrderStatusEnum.IN_PROGRESS, ProfitConditionStatusEnum.INCOMPLETE);
            // 若未达到结算标准且首充金额不为空则订单失败，原因为 首充未达标
            String scMoney = refreshOrderBo.getScMoney();
            if (!StringUtils.isBlank(scMoney) && Float.parseFloat(scMoney) > 0){
                defaultProfitConditionBO.setStatus("-1");
                refreshOrderBo.setStatusMsg("首充不达标");
            }
        }
        // 判断订单失败
        if (isFail(defaultProfitConditionBO)) {
            refreshOrderBo.setFailureReason(refreshOrderBo.getStatusMsg());
            cmccDaOrderService.updateOrderByRefreshOrderBO(refreshOrderBo, OrderStatusEnum.FAIL, ProfitConditionStatusEnum.INCOMPLETE);
        }
    }
    /**
     * 判断订单信息 是否为失败状态
     * @param defaultProfitConditionBO 默认条件判断参数
     * @return 订单状态为失败 返回 true 反正返回 false
     */
    private boolean isFail(DefaultProfitConditionBO defaultProfitConditionBO) {
        return defaultProfitConditionBO.getStatus().equals("-1");
    }
    /**
     * 判断该比订单是否满足获利条件
     * @param defaultProfitConditionBO 所需参数
     */
    private boolean isSatisfyProfitCondition(CmccDaOrder cmccDaOrder, DefaultProfitConditionBO defaultProfitConditionBO) {
//        log.info("判断订单是否满足激活条件{}", defaultProfitConditionBO.toString());
        orderRefreshLog.info("判断订单是否满足激活条件{}", defaultProfitConditionBO.toString());
        if (!Objects.isNull(cmccDaOrder)) {
            defaultProfitConditionBO.setProductParam(cmccDaOrder.getProductParam());
            defaultProfitConditionBO.setProductTypeId(cmccDaOrder.getProductTypeId());
            DefaultProfitConditionEnum enumByCode = DefaultProfitConditionEnum.getEnumByCode(cmccDaOrder.getProfitConditionId());
            ProfitCondition<DefaultProfitConditionBO> profitCondition = enumByCode.getProfitCondition();
            return profitCondition.condition(defaultProfitConditionBO);
        } else {
            return false;
        }
    }

    @Override
    public void refreshChannelCommission(CmccDaUpChannelInfo cmccDaUpChannelInfo) {
        Channel defaultChannel = channelManager.getDefaultChannel(cmccDaUpChannelInfo.getChannelId());
        defaultChannel.refreshChannelCommission(cmccDaUpChannelInfo);
    }



/** ============================================================= 统计相关 =============================================================== */
    @Override
    public LineChartDataVO getTodayOrderCount(CmccDaOrderListReq cmccDaOrderListReq) {
        DateTime currentDate = DateUtil.date();
        CmccDaOrderListDTO cmccDaOrderListDTO = cmccDaOrderWebConverter.cmccDaOrderListReqToDto(cmccDaOrderListReq);
        cmccDaOrderListDTO.setBeginTime(DateUtil.beginOfDay(currentDate).toLocalDateTime());
        cmccDaOrderListDTO.setEndTime(DateUtil.endOfDay(currentDate).toLocalDateTime());
//        cmccDaOrderListDTO.setBeginTime(DateUtil.parse("2024-11-01 00:00:00").toLocalDateTime());
//        cmccDaOrderListDTO.setEndTime(DateUtil.parse("2024-12-01 00:00:00").toLocalDateTime());
        return getOrderCountData(cmccDaOrderListDTO);
    }

    @Override
    public LineChartDataVO getYesterdayOrderCount(CmccDaOrderListReq cmccDaOrderListReq) {
        DateTime currentDate = DateUtil.yesterday();
        CmccDaOrderListDTO cmccDaOrderListDTO = cmccDaOrderWebConverter.cmccDaOrderListReqToDto(cmccDaOrderListReq);
        cmccDaOrderListDTO.setBeginTime(DateUtil.beginOfDay(currentDate).toLocalDateTime());
        cmccDaOrderListDTO.setEndTime(DateUtil.endOfDay(currentDate).toLocalDateTime());
        return getOrderCountData(cmccDaOrderListDTO);
    }

    @Override
    public LineChartDataVO getWeekOrderCount(CmccDaOrderListReq cmccDaOrderListReq) {
        DateTime currentDate = DateUtil.date();
        CmccDaOrderListDTO cmccDaOrderListDTO = cmccDaOrderWebConverter.cmccDaOrderListReqToDto(cmccDaOrderListReq);
        cmccDaOrderListDTO.setBeginTime(DateUtil.beginOfWeek(currentDate, true).toLocalDateTime());
        cmccDaOrderListDTO.setEndTime(DateUtil.endOfWeek(currentDate, true).toLocalDateTime());
        return getOrderCountData(cmccDaOrderListDTO);
    }

    @Override
    public LineChartDataVO getMonthOrderCount(CmccDaOrderListReq cmccDaOrderListReq) {
        DateTime currentDate = DateUtil.date();
        CmccDaOrderListDTO cmccDaOrderListDTO = cmccDaOrderWebConverter.cmccDaOrderListReqToDto(cmccDaOrderListReq);
        cmccDaOrderListDTO.setBeginTime(DateUtil.beginOfMonth(currentDate).toLocalDateTime());
        cmccDaOrderListDTO.setEndTime(DateUtil.endOfMonth(currentDate).toLocalDateTime());
        return getOrderCountData(cmccDaOrderListDTO);
    }

    @Override
    public LineChartDataVO getCustomOrderCount(CmccDaOrderListReq cmccDaOrderListReq) {
        CmccDaOrderListDTO cmccDaOrderListDTO = cmccDaOrderWebConverter.cmccDaOrderListReqToDto(cmccDaOrderListReq);
        return getOrderCountData(cmccDaOrderListDTO);
    }

    public LineChartDataVO getOrderCountData(CmccDaOrderListDTO cmccDaOrderListDTO) {
        Date currentDate = new Date();
        LocalDateTime beginTime = cmccDaOrderListDTO.getBeginTime() == null ? DateUtil.beginOfDay(currentDate).toLocalDateTime() : cmccDaOrderListDTO.getBeginTime();
        LocalDateTime endTime = cmccDaOrderListDTO.getEndTime() == null ? DateUtil.endOfDay(currentDate).toLocalDateTime() :cmccDaOrderListDTO.getEndTime();
        DateTime startDateTime = new DateTime(beginTime);
        DateTime endDateTime = new DateTime(endTime);
        if (DateUtil.compare(startDateTime, endDateTime) > 0){
            throw new ServiceException("开始时间不能大于结束时间");
        }
        if (DateUtil.between(startDateTime, endDateTime, DateUnit.HOUR) < 1){
            throw new ServiceException("暂不支持小时内统计");
        }
        LineChartDataVO lineChartDataVO = new LineChartDataVO();
        cmccDaOrderListDTO.setBeginTime(DateUtil.beginOfDay(startDateTime).toLocalDateTime());
        cmccDaOrderListDTO.setEndTime(DateUtil.endOfDay(endDateTime).toLocalDateTime());
        // 获取指定时间内订单数据
        List<CmccDaOrder> orderList = new ArrayList<>();
        // 自己的订单
        SysUser currentSysUser = sysUserMapper.selectUserById(getUserId());
        if (currentSysUser.isAdmin()) return null;
        if (!currentSysUser.isOperationSupervisor() && !currentSysUser.isAgentOperation()){
            orderList = cmccDaOrderService.listCmccDaOrder(cmccDaOrderListDTO);
        }
        // 添加下级订单
        List<Long> userList = cmccDaSubordinateOrderService.getSubordinateUserIdList();
        if (userList != null && !userList.isEmpty()) {
            cmccDaOrderListDTO.setUserIdList(userList);
            orderList.addAll(cmccDaSubordinateOrderService.listCmccDaSubordinateOrder(cmccDaOrderListDTO));
        }
        if (orderList.isEmpty()){
            return null;
        }
        // 日期列表
        List<DateTime> dateList = new LinkedList<>();
        // 日期字符串列表
        List<String> dateStrList = new LinkedList<>();
        // 当月订单数量
        List<List<CmccDaOrder>> orderCountList = new LinkedList<>();
        // 周一到周日map
        Map<Integer, String> weekMap = new HashMap<Integer, String>(){
            {
                put(1, "周日");
                put(2, "周一");
                put(3, "周二");
                put(4, "周三");
                put(5, "周四");
                put(6, "周五");
                put(7, "周六");
            }
        };
        // 查询时间在24小时之内
        if (DateUtil.between(startDateTime, endDateTime, DateUnit.HOUR) < 24){
            dateList = DateUtil.rangeToList(startDateTime, endDateTime, DateField.HOUR);
            // 循环
            for (int i = 1; i < dateList.size(); i++) {
                DateTime date = dateList.get(i);
                //System.out.println("date = " + date);
                dateStrList.add(DateUtil.format(date, "MM-dd HH:mm"));
                List<CmccDaOrder> orderCounts = orderList.stream().filter(f -> f.getCreateTime().isBefore(date.toLocalDateTime())
                        && f.getCreateTime().isAfter(DateUtil.offsetHour(date, -1).toLocalDateTime())).collect(Collectors.toList());
                orderCountList.add(orderCounts);
            }
            // 加上24点
            dateStrList.add(DateUtil.format(endDateTime, "MM-dd") + " 24:00");
            List<CmccDaOrder> orderCounts = orderList.stream().filter(f -> f.getCreateTime().isBefore(endDateTime.toLocalDateTime())
                    && f.getCreateTime().isAfter(DateUtil.offsetHour(endDateTime, -1).toLocalDateTime())).collect(Collectors.toList());
            orderCountList.add(orderCounts);
        } else if (DateUtil.between(startDateTime, endDateTime, DateUnit.DAY) <= 7) {
            dateList = DateUtil.rangeToList(startDateTime, endDateTime, DateField.DAY_OF_WEEK);
            // 循环
            for (DateTime date : dateList) {
                //System.out.println("date = " + weekMap.get(DateUtil.dayOfWeek(date)));
                dateStrList.add(weekMap.get(DateUtil.dayOfWeek(date)));
                List<CmccDaOrder> orderCounts = orderList.stream().filter(f -> f.getCreateTime().isAfter(DateUtil.beginOfDay(date).toLocalDateTime())
                        && f.getCreateTime().isBefore(DateUtil.endOfDay(date).toLocalDateTime())).collect(Collectors.toList());
                orderCountList.add(orderCounts);
            }
        } else{
            dateList = DateUtil.rangeToList(startDateTime, endDateTime, DateField.DAY_OF_MONTH);
            // 循环
            for (DateTime date : dateList) {
                //System.out.println("date = " + date);
                dateStrList.add(DateUtil.format(date, "MM-dd"));
                List<CmccDaOrder> orderCounts = orderList.stream().filter(f -> f.getCreateTime().isAfter(DateUtil.beginOfDay(date).toLocalDateTime())
                        && f.getCreateTime().isBefore(DateUtil.endOfDay(date).toLocalDateTime())).collect(Collectors.toList());
                orderCountList.add(orderCounts);
            }
        }
        lineChartDataVO.setXAxis(dateStrList);
        List<Integer> allCountList = new LinkedList<>();
        List<Integer> successCountList = new LinkedList<>();
        List<Integer> processCountList = new LinkedList<>();
        List<Integer> failCountList = new LinkedList<>();
        List<Integer> placeCountList = new LinkedList<>();
        for (List<CmccDaOrder> cmccDaOrderList : orderCountList) {
            allCountList.add(cmccDaOrderList.size());
            successCountList.add((int) cmccDaOrderList.stream().filter(f -> "3".equals(f.getOrderStatus())).count());
            processCountList.add((int) cmccDaOrderList.stream().filter(f -> "2".equals(f.getOrderStatus())).count());
            failCountList.add((int) cmccDaOrderList.stream().filter(f -> "0".equals(f.getOrderStatus())).count());
            placeCountList.add((int) cmccDaOrderList.stream().filter(f -> "1".equals(f.getOrderStatus())).count());
        }
        lineChartDataVO.setAll(allCountList);
        lineChartDataVO.setSuccess(successCountList);
        lineChartDataVO.setProcess(processCountList);
        lineChartDataVO.setFail(failCountList);
        lineChartDataVO.setPlace(placeCountList);
        lineChartDataVO.setAllCount(allCountList.stream().reduce(0, Integer::sum));
        lineChartDataVO.setSuccessCount(successCountList.stream().reduce(0, Integer::sum));
        lineChartDataVO.setProcessCount(processCountList.stream().reduce(0, Integer::sum));
        lineChartDataVO.setFailCount(failCountList.stream().reduce(0, Integer::sum));
        lineChartDataVO.setPlaceCount(placeCountList.stream().reduce(0, Integer::sum));
        // 各省份数据
        Map<String, List<CmccDaOrder>> provinceOrderMap = orderList.stream().filter(f -> !"0".equals(f.getOrderStatus()))
                .collect(Collectors.groupingBy(CmccDaOrder::getAddressProvince));
        Map<String, Integer> provinceOrderCountMap = new HashMap<>();
        for (Map.Entry<String, List<CmccDaOrder>> entry : provinceOrderMap.entrySet()) {
            provinceOrderCountMap.put(entry.getKey(), entry.getValue().size());
        }
        lineChartDataVO.setProvinceOrderCountMap(provinceOrderCountMap);
        return lineChartDataVO;
    }


























    /*private LineChartDataVO getOrderCountByDate(Date currentDate) {
        LineChartDataVO lineChartDataVO = new LineChartDataVO();
        lineChartDataVO.setXAxis(new ArrayList<>(Arrays.asList("8:00","10:00","12:00","14:00","16:00","18:00","20:00","22:00","24:00")));
        DateTime todayBeginTime = DateUtil.beginOfDay(currentDate);
        DateTime todayEndTime = DateUtil.endOfDay(currentDate);
        DateTime todayTime8 = DateUtil.beginOfDay(currentDate).offset(DateField.HOUR_OF_DAY, 8);
        DateTime todayTime10 = DateUtil.beginOfDay(currentDate).offset(DateField.HOUR_OF_DAY, 10);
        DateTime todayTime12 = DateUtil.beginOfDay(currentDate).offset(DateField.HOUR_OF_DAY, 12);
        DateTime todayTime14 = DateUtil.beginOfDay(currentDate).offset(DateField.HOUR_OF_DAY, 14);
        DateTime todayTime16 = DateUtil.beginOfDay(currentDate).offset(DateField.HOUR_OF_DAY, 16);
        DateTime todayTime18 = DateUtil.beginOfDay(currentDate).offset(DateField.HOUR_OF_DAY, 18);
        DateTime todayTime20 = DateUtil.beginOfDay(currentDate).offset(DateField.HOUR_OF_DAY, 20);
        DateTime todayTime22 = DateUtil.beginOfDay(currentDate).offset(DateField.HOUR_OF_DAY, 22);
        DateTime todayTime24 = DateUtil.beginOfDay(currentDate).offset(DateField.HOUR_OF_DAY, 24);
        CmccDaOrderListDTO cmccDaOrderListDTO = new CmccDaOrderListDTO();
        List<Long> userList = cmccDaSubordinateOrderService.getSubordinateUserIdList();
        cmccDaOrderListDTO.setUserIdList(userList);
        cmccDaOrderListDTO.setBeginTime(todayBeginTime.toLocalDateTime());
        cmccDaOrderListDTO.setEndTime(todayEndTime.toLocalDateTime());
        List<CmccDaOrder> orderList = cmccDaSubordinateOrderService.listCmccDaSubordinateOrder(cmccDaOrderListDTO);
        List<List<CmccDaOrder>> timeOrderCountList = new LinkedList<>();
        List<CmccDaOrder> orderCount8 = orderList.stream().filter(f -> f.getCreateTime().isAfter(todayBeginTime.toLocalDateTime())
                && f.getCreateTime().isBefore(todayTime8.toLocalDateTime())).collect(Collectors.toList());
        timeOrderCountList.add(orderCount8);
        List<CmccDaOrder> orderCount10 = orderList.stream().filter(f -> f.getCreateTime().isAfter(todayTime8.toLocalDateTime())
                && f.getCreateTime().isBefore(todayTime10.toLocalDateTime())).collect(Collectors.toList());
        timeOrderCountList.add(orderCount10);
        List<CmccDaOrder> orderCount12 = orderList.stream().filter(f -> f.getCreateTime().isAfter(todayTime10.toLocalDateTime())
                && f.getCreateTime().isBefore(todayTime12.toLocalDateTime())).collect(Collectors.toList());
        timeOrderCountList.add(orderCount12);
        List<CmccDaOrder> orderCount14 = orderList.stream().filter(f -> f.getCreateTime().isAfter(todayTime12.toLocalDateTime())
                && f.getCreateTime().isBefore(todayTime14.toLocalDateTime())).collect(Collectors.toList());
        timeOrderCountList.add(orderCount14);
        List<CmccDaOrder> orderCount16 = orderList.stream().filter(f -> f.getCreateTime().isAfter(todayTime14.toLocalDateTime())
                && f.getCreateTime().isBefore(todayTime16.toLocalDateTime())).collect(Collectors.toList());
        timeOrderCountList.add(orderCount16);
        List<CmccDaOrder> orderCount18 = orderList.stream().filter(f -> f.getCreateTime().isAfter(todayTime16.toLocalDateTime())
                && f.getCreateTime().isBefore(todayTime18.toLocalDateTime())).collect(Collectors.toList());
        timeOrderCountList.add(orderCount18);
        List<CmccDaOrder> orderCount20 = orderList.stream().filter(f -> f.getCreateTime().isAfter(todayTime18.toLocalDateTime())
                && f.getCreateTime().isBefore(todayTime20.toLocalDateTime())).collect(Collectors.toList());
        timeOrderCountList.add(orderCount20);
        List<CmccDaOrder> orderCount22 = orderList.stream().filter(f -> f.getCreateTime().isAfter(todayTime20.toLocalDateTime())
                && f.getCreateTime().isBefore(todayTime22.toLocalDateTime())).collect(Collectors.toList());
        timeOrderCountList.add(orderCount22);
        List<CmccDaOrder> orderCount24 = orderList.stream().filter(f -> f.getCreateTime().isAfter(todayTime22.toLocalDateTime())
                && f.getCreateTime().isBefore(todayTime24.toLocalDateTime())).collect(Collectors.toList());
        timeOrderCountList.add(orderCount24);
        List<Integer> allCountList = new LinkedList<>();
        List<Integer> successCountList = new LinkedList<>();
        List<Integer> processCountList = new LinkedList<>();
        List<Integer> failCountList = new LinkedList<>();
        List<Integer> placeCountList = new LinkedList<>();
        for (List<CmccDaOrder> cmccDaOrderList : timeOrderCountList) {
            allCountList.add(cmccDaOrderList.size());
            successCountList.add((int) cmccDaOrderList.stream().filter(f -> "3".equals(f.getOrderStatus())).count());
            processCountList.add((int) cmccDaOrderList.stream().filter(f -> "2".equals(f.getOrderStatus())).count());
            failCountList.add((int) cmccDaOrderList.stream().filter(f -> "0".equals(f.getOrderStatus())).count());
            placeCountList.add((int) cmccDaOrderList.stream().filter(f -> "1".equals(f.getOrderStatus())).count());
        }
        lineChartDataVO.setAll(allCountList);
        lineChartDataVO.setSuccess(successCountList);
        lineChartDataVO.setProcess(processCountList);
        lineChartDataVO.setFail(failCountList);
        lineChartDataVO.setPlace(placeCountList);
        lineChartDataVO.setAllCount(allCountList.stream().reduce(0, Integer::sum));
        lineChartDataVO.setSuccessCount(successCountList.stream().reduce(0, Integer::sum));
        lineChartDataVO.setProcessCount(processCountList.stream().reduce(0, Integer::sum));
        lineChartDataVO.setFailCount(failCountList.stream().reduce(0, Integer::sum));
        lineChartDataVO.setPlaceCount(placeCountList.stream().reduce(0, Integer::sum));
        return lineChartDataVO;
    }*/
}
